package org.apache.ibatis.common.io;

import java.io.InputStream;
import java.net.URL;

/**
 * @Name ClassLoaderWrapper
 * @Description: 类加载器 [包装] 类
 * 描述信息：该类中封装了 5 种类加载器，用于将类文件加载成类。
 * 这 5 种类加载器依次是：
 * - 作为参数传入的类加载器，可能为 null；
 * - 系统默认的类加载器，如未设置则为 null；
 * - 当前线程的线程上下文中的类加载器；
 * - 当前对象的类加载器；
 * - 系统类加载器。
 * @Version v1.0.0
 * @Author: lichao
 * @Date: 2024-05-14 18:07:43
 **/
public class ClassLoaderWrapper {
    ClassLoader defaultClassLoader, systemClassLoader;

    ClassLoaderWrapper() {
        try {
            systemClassLoader = ClassLoader.getSystemClassLoader();
        } catch (SecurityException ignored) {
        }
    }

    public Class<?> classForName(String name) throws ClassNotFoundException {
        return classForName(name, getClassLoaders(null));
    }

    public Class<?> classForName(String name, ClassLoader classLoader) throws ClassNotFoundException {
        return classForName(name, getClassLoaders(classLoader));
    }

    Class<?> classForName(String name, ClassLoader[] classLoaders) throws ClassNotFoundException {
        for (ClassLoader classLoader : classLoaders) {
            if (null != classLoader) {
                try {
                    // 首先尝试使用当前类加载器进行加载
                    Class<?> clazz = Class.forName(name, true, classLoader);
                    if (null != clazz) return clazz;
                } catch (ClassNotFoundException e) {
                    // 本处忽略该异常，因为这只是在某一个类加载器中没有找到目标类。
                }
            }
        }
        // 在所有类加载器中均没有发现目标类，抛出异常。
        throw new ClassNotFoundException("没有发现目标类：" + name);
    }

    public URL getResourceAsURL(String resource) {
        return getResourceAsURL(resource, getClassLoaders(null));
    }

    public URL getResourceAsURL(String resource, ClassLoader classLoader) {
        return getResourceAsURL(resource, getClassLoaders(classLoader));
    }

    URL getResourceAsURL(String resource, ClassLoader[] classLoaders) {
        URL url;
        for (ClassLoader classLoader : classLoaders) {
            if (null != classLoader) {
                url = classLoader.getResource(resource);
                if (null == url) url = classLoader.getResource("/" + resource);
                if (null != url) return url;
            }
        }
        return null;
    }

    public InputStream getResourceAsInputStream(String resource) {
        return getResourceAsInputStream(resource, getClassLoaders(null));
    }

    public InputStream getResourceAsInputStream(String resource, ClassLoader classLoader) {
        return getResourceAsInputStream(resource, getClassLoaders(classLoader));
    }

    InputStream getResourceAsInputStream(String resource, ClassLoader[] classLoaders) {
        for (ClassLoader classLoader : classLoaders) {
            if (null != classLoader) {
                InputStream returnValue = classLoader.getResourceAsStream(resource);
                if (null == returnValue) returnValue = classLoader.getResourceAsStream("/" + resource);
                if (null != returnValue) return returnValue;
            }
        }
        return null;
    }

    ClassLoader[] getClassLoaders(ClassLoader classLoader) {
        return new ClassLoader[]{
                classLoader,
                defaultClassLoader,
                Thread.currentThread().getContextClassLoader(),
                getClass().getClassLoader(),
                systemClassLoader
        };
    }

}

